package krao.data;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * Union of conjunctive queries.
 * 
 * @author Pepe
 * @see ConjQuery
 */
public class UnionConjQuery {
	private ArrayList<ConjQuery> queries;

	public UnionConjQuery() {
		queries = new ArrayList<ConjQuery>();
	}

	public void clear() {
		queries.clear();
	}

	public void addQuery(ConjQuery cq) {
		queries.add(cq);
	}

	@Override
	public String toString() {
		return toStringQueryForm();
		/*
		 * if (queries.size() == 0) { return "UCQ[0]:\n"; } else { StringBuilder
		 * sb = new StringBuilder(String.format("\nUCQ[%s]:\n",
		 * queries.size())); for (ConjQuery cq : queries) {
		 * sb.append(cq.toString()); sb.append("\n"); } return sb.toString(); }
		 */
	}

	public String toStringQueryForm() {
		StringBuilder sb = new StringBuilder();
		for (ConjQuery cq : queries) {
			sb.append(cq.toStringQueryForm());
			sb.append("\n");
		}
		return sb.toString();
	}

	public ArrayList<ConjQuery> getQueries() {
		return queries;
	}

	/**
	 * Merges in newQueries into this union.
	 * 
	 * @param newQueries
	 *            queries to be merged in
	 * @return were some queries added?
	 */
	public boolean mergeIn(UnionConjQuery newQueries) {
		boolean changed = false;
		for (ConjQuery cq : newQueries.queries) {
			if (!this.queries.contains(cq)) {
				this.queries.add(cq);
				changed = true;
			}
		}
		return changed;

		// if all new queries are already included
		/*
		 * if (this.hasSubset(newQueries)) { return false; } else { return
		 * queries.addAll(newQueries.queries); // return true; }
		 */
	}

	/**
	 * Remove queries, which are invalid.
	 * 
	 * @see {@link krao.data.ConjQuery#isInvalid()}
	 */
	public void removeInvalidQueries() {
		HashSet<ConjQuery> invalidQueries = new HashSet<ConjQuery>();
		for (ConjQuery query : queries) {
			if (query.isInvalid()) {
				invalidQueries.add(query);
			}
		}

		if (invalidQueries.size() > 0) {
			for (ConjQuery invalidQuery : invalidQueries) {
				queries.remove(invalidQuery);
			}
		}

	}

	@Override
	public boolean equals(Object o) {
		if (o == null) {
			return false;
		}
		UnionConjQuery other = (UnionConjQuery) o;

		if (this.queries.size() == other.queries.size()) {
			ArrayList<ConjQuery> otherQueries = other.queries;
			for (ConjQuery query : this.queries) {
				if (!otherQueries.contains(query)) {
					return false;
				}
			}

			for (ConjQuery query : otherQueries) {
				if (!this.queries.contains(query)) {
					return false;
				}
			}
			// all queries from this union are contained in the second union and
			// vice versa
			return true;
		}
		return false;
	}

	/**
	 * Check whether the provided union is a subset of this one
	 * 
	 * @param ucq
	 *            subset to be checked
	 * @return true if ucq is subset of this, false otherwise
	 */
	public boolean hasSubset(UnionConjQuery ucq) {
		for (ConjQuery query : ucq.queries) {
			// if there is some query in ucq, that is not here, ucq is not
			// subset
			if (!this.queries.contains(query)) {
				return false;
			}
		}
		// all queries from ucq are contained in this union
		return true;
	}

	/**
	 * Calls the anonymize function for all queries contains in this union.
	 */
	public void anonymize() {
		for (ConjQuery query : this.queries) {
			query.anonymize();
		}
	}

	@Override
	public int hashCode() {
		return this.toString().hashCode();
	}

	public boolean isEmpty() {
		return this.queries == null || this.queries.isEmpty();
	}
}
